Fault injection (FI) is commonly used for evaluating the resilience of systems. Existing FI approaches, however, involve a significant amount of manual decision making, such as determining, for example, what type of errors should be injected, when a fault should be injected, which object, component, process, and/or software-stack-level should be the target of the fault injection, which value and/or variable in the target object, component, process, and/or software-stack-level should be injected with what erroneous value, and what workload should be used for fault injection trials. Such approaches, accordingly, are inefficient, costly and time-consuming to carry out.